﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace HDJ.Framework.Core
{
    public   class GameSceneManager 
    {

        private static  Dictionary<string, GameSceneBase> allScenes = new Dictionary<string, GameSceneBase>();
        private static Dictionary<string, Type> allSceneTypes = new Dictionary<string, Type>();
        //private static GameSceneManager instance;

        public static GameSceneBase currentScene;
        public static string[] AllSceneNames
        {
            get
            {
                if (allSceneTypes.Count == 0)
                {
                    GetAllSceneType();
                }
                return new List<string>(allSceneTypes.Keys).ToArray();
            }
        }

        public static void Init()
        {
            GetAllSceneType();

            MonoBehaviourRuntime.Instance.OnFixedUpdate += OnFixedUpdate;
            MonoBehaviourRuntime.Instance.OnLateUpdate += OnLateUpdate;
            MonoBehaviourRuntime.Instance.OnUpdate += OnUpdate;
            MonoBehaviourRuntime.Instance.OnGUIUpdate += OnGUIUpdate;
            MonoBehaviourRuntime.Instance.OnApplicationExit += OnApplicationExit;
        }
        private static void GetAllSceneType()
        {
            allSceneTypes.Clear();

            Type[] types = ReflectionUtils.GetChildTypes(typeof(GameSceneBase));
            for (int i = 0; i < types.Length; i++)
            {
                Type t = types[i];
                allSceneTypes.Add(t.Name, t);

            }
        }

        public static T GetScene<T>()where T:GameSceneBase
        {
            GameSceneBase gameScene = GetScene(typeof(T).Name);
            if (gameScene == null)
                return null;
            else
                return (T)gameScene;
        }
        public static GameSceneBase GetScene(string name)
        {
            if (allScenes.ContainsKey(name))
            {
                return allScenes[name];
            }
            Debug.LogError("dont have Scene:"+name);
            return null;
        }
        /// <summary>
        /// 开启新的场景
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="isForceOpen">false：如果当前场景与将要打开场景相同则不做任何处理</param>
        public static void OpenScene<T>(bool isForceOpen=false)
        {
            OpenScene(typeof(T).Name,isForceOpen);
        }
        private static string OpenNextSceneName;
        public static void OpenScene(string sceneName,bool isForceOpen = false)
        {
            if (currentScene!=null&& sceneName == currentScene.GetType().Name && !isForceOpen)
                return;
            Debug.Log("OpenScene>>" + sceneName);
            OpenNextSceneName = sceneName;
        }
        private static void OpenningScene(string sceneName)
        {
            if (allSceneTypes.ContainsKey(sceneName) && !allScenes.ContainsKey(sceneName))
            {
                Type t = allSceneTypes[sceneName];
                object temp = Activator.CreateInstance(t);
                GameSceneBase sceneBase = (GameSceneBase)temp;
                allScenes.Add(t.Name, sceneBase);
                sceneBase.OnCreate();
            }
            if (allScenes.ContainsKey(sceneName))
            {
                if (isChangingScene)
                {
                    Debug.LogError(" is Changing Scene,can't Change to :" + sceneName);
                    return;
                }

                MonoBehaviourRuntime.Instance.StartCoroutine(ChangeScene(sceneName));
            }
            else
            {
                Debug.LogError("GameFlowControlSystem.OpenScene :" + sceneName + "  failed!, no such Scene");
            }
        }
        private static bool isChangingScene = false;
        private static IEnumerator ChangeScene(string nextScene)
        {
            isChangingScene = true;
            if (currentScene != null)
            {
                currentScene.OnExitEx();
            }

            currentScene = allScenes[nextScene];

            currentScene.OnOpen();
            yield return currentScene.OnLoadAssets();

            isChangingScene = false;
        }

        protected static void OnFixedUpdate()
        {
            if (currentScene != null)
            {
                currentScene.OnFixedUpdate();
            }
        }

        protected static void OnLateUpdate()
        {
            if (currentScene != null)
            {
                currentScene.OnLateUpdate();
            }
        }

        protected static void OnUpdate()
        {
            if (!string.IsNullOrEmpty(OpenNextSceneName))
            {
                OpenningScene(OpenNextSceneName);
                OpenNextSceneName = "";
            }
            if (currentScene != null)
            {
                currentScene.OnUpdate();
            }
        }

        protected static void OnGUIUpdate()
        {
            if (currentScene != null)
            {
                currentScene.OnGUIUpdate();
            }
        }
        private static void OnApplicationExit()
        {
            if (currentScene != null)
            {
                currentScene.OnApplicationExit();
            }
        }
    }
}
